﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;

namespace AAA.Base.Util
{
    public class ZipHelper
    {
        private static ArrayList GenerateFileList(string Dir)
        {
            ArrayList fils = new ArrayList();
            bool Empty = true;
            foreach (string file in Directory.GetFiles(Dir)) // add each file in directory
            {
                fils.Add(file);
                Empty = false;
            }

            if (Empty)
            {
                if (Directory.GetDirectories(Dir).Length == 0)
                // if directory is completely empty, add it
                {
                    fils.Add(Dir + @"/");
                }
            }

            foreach (string dirs in Directory.GetDirectories(Dir)) // recursive
            {
                foreach (object obj in GenerateFileList(dirs))
                {
                    fils.Add(obj);
                }
            }
            return fils; // return file list
        }

        public static void ZipFiles(string inputFolderPath, string outputPathAndFile, string password)
        {
            ArrayList ar = GenerateFileList(inputFolderPath); // generate file list
            int TrimLength = (Directory.GetParent(inputFolderPath)).ToString().Length;
            // find number of chars to remove     // from orginal file path
            TrimLength += 1; //remove '\'
            FileStream ostream;
            byte[] obuffer;
            //string outPath = inputFolderPath + @"\" + outputPathAndFile;
            string outPath = outputPathAndFile;
            ZipOutputStream oZipStream = new ZipOutputStream(File.Create(outPath)); // create zip stream
            if (password != null && password != String.Empty)
                oZipStream.Password = password;
            oZipStream.SetLevel(9); // maximum compression
            ZipEntry oZipEntry;
            foreach (string Fil in ar) // for each file, generate a zipentry
            {
                oZipEntry = new ZipEntry(Fil.Remove(0, TrimLength));
                oZipStream.PutNextEntry(oZipEntry);

                if (!Fil.EndsWith(@"/")) // if a file ends with '/' its a directory
                {
                    ostream = File.OpenRead(Fil);
                    obuffer = new byte[ostream.Length];
                    ostream.Read(obuffer, 0, obuffer.Length);
                    oZipStream.Write(obuffer, 0, obuffer.Length);
                }
            }
            oZipStream.Finish();
            oZipStream.Close();
        }

        public static List<string> ListFiles(string strZipFile)
        {
            List<string> lstFile;

            if (File.Exists(strZipFile) == false)
                return null;

            lstFile = new List<string>();

            ZipFile zip = new ZipFile(strZipFile);

            foreach (ZipEntry entry in zip)
                if (entry.IsFile)
                    lstFile.Add(entry.Name);

            return lstFile;
        }

        private static string GetBaseName(string strFullName)
        {
            return strFullName.IndexOf("\\") < 0
                    ?   strFullName
                    :   strFullName.Substring(strFullName.LastIndexOf("\\") + 1);
        }

        public static void Uncompress(string strZipFileNmae, string strTargetPath)
        {
            ZipInputStream zipInputStream = new ZipInputStream(File.OpenRead(strZipFileNmae));
            FileStream fs = null;
            int iSize = 4096;
            byte[] bData = new byte[4096];

            if (Directory.Exists(strTargetPath) == false)
                Directory.CreateDirectory(strTargetPath);

            ZipEntry zipEntry;

            try
            {
                while ((zipEntry = zipInputStream.GetNextEntry()) != null)
                {
                    try
                    {
                        fs = new FileStream(strTargetPath + "\\" + GetBaseName(zipEntry.Name), FileMode.Create);

                        while ((iSize = zipInputStream.Read(bData, 0, bData.Length)) > 0)
                            fs.Write(bData, 0, iSize);

                    }
                    catch (Exception ex)
                    {
                        if (fs != null)
                            fs.Close();

                        throw;
                    }
                    finally
                    {
                        if (fs != null)
                            fs.Close();
                        
                    }
                }
            }
            catch (Exception ex)
            {
                if (fs != null)
                    fs.Close();
                zipInputStream.Close();
                throw;                
            }
            finally
            {
                if (fs != null)
                    fs.Close();
                zipInputStream.Close();
            }
        }

    }
}
